﻿namespace PugLib.Threading
{
    // Notices: Written by Jeffrey Richter

    using System;
    using System.Threading;

    public sealed class LongTask
    {
        private readonly Int32 _milliseconds;

        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2233:OperationsShouldNotOverflow", MessageId = "seconds*1000")]
        public LongTask(Int32 seconds)
        {
            _milliseconds = seconds * 1000;
        }

        // Synchronous version of time-consuming method
        public DateTime DoTask()
        {
            Thread.Sleep(_milliseconds); // Simulate time-consuming task
            return DateTime.Now; // Return value indicates when task completed
        }

        // Asynchronous version of time-consuming method (Begin part)
        public IAsyncResult BeginDoTask(AsyncCallback callback, Object state)
        {
            // Create IAsyncResult object identifying the asynchronous operation
            AsyncResult<DateTime> ar = new AsyncResult<DateTime>(callback, state);

            // Use a thread pool thread to perform the operation
            ThreadPool.QueueUserWorkItem(DoTaskHelper, ar);

            return ar; // Return the IAsyncResult to the caller
        }

        // Asynchronous version of time-consuming method (End part)
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1822:MarkMembersAsStatic")]
        public DateTime EndDoTask(IAsyncResult asyncResult)
        {
            // We know that the IAsyncResult is really an AsyncResult<DateTime> object
            AsyncResult<DateTime> ar = (AsyncResult<DateTime>)asyncResult;

            // Wait for operation to complete, then return result or throw exception
            return ar.EndInvoke();
        }

        // Asynchronous version of time-consuming method (private part to set completion result/exception)
        private void DoTaskHelper(Object asyncResult)
        {
            // We know that the IAsyncResult is really an AsyncResult<DateTime> object
            AsyncResult<DateTime> ar = (AsyncResult<DateTime>)asyncResult;
            try
            {
                // Perform the operation; if sucessful set the result
                ar.SetAsCompleted(DoTask(), false);
            }
            catch (Exception e)
            {
                // If operation fails, set the exception
                ar.SetAsCompleted(e, false);
            }
        }
    }
}